package com.example.tfliteonwatch;

import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;

import android.Manifest;
import android.annotation.SuppressLint;
import android.content.Intent;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.os.Environment;
import android.util.Log;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.TextView;

import org.tensorflow.lite.Interpreter;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.ReentrantLock;

public class testing extends AppCompatActivity {

    private TextView text1;
    private TextView remainTime;
    private TextView showaction;
    private Button lalala;

    public class accdata {   //加速度
        public float x;
        public float y;
        public float z;
        public long timestamp;
    }

    public class grydata {   //陀螺仪
        public float x;
        public float y;
        public float z;
        public long timestamp;
    }
//    ArrayList<accdata> acclist = new ArrayList<accdata>();
    public static List<accdata> acclist = Collections.synchronizedList(new ArrayList<accdata>());//存数据的数组
    public static List<grydata> grylist = Collections.synchronizedList(new ArrayList<grydata>());
//    ArrayList<grydata> grylist = new ArrayList<grydata>();
    private CountDownTimer timer;
    private SensorManager mSensorManager;         //必须有 拿传感器数据
    private MySensorEventListener mMySensorEventListener;  //必须有 拿传感器数据
    ActivityResultLauncher<String> permissionLauncher;
    private float[] mAccelerometerReading = new float[3];  //没什么用
    private float[] mMagneticFieldReading = new float[3];  //没什么用
    private int flag;
    private String actionnow;
    private ArrayList<String> threadlist=new ArrayList<>();
    private String actionpredict;
    private int actionindex=-1;
    Interpreter mInterpreter;
    Interpreter mInterpreter2;
    Interpreter mInterpreter3;
    @SuppressLint("MissingInflatedId")
    ReentrantLock lock = new ReentrantLock();
    Interpreter retoreModel(){
        try (Interpreter anotherInterpreter =TFLiteLoader.newInstance(getApplicationContext()).get("trainable_model.tflite")) {
            // Load the trained weights from the checkpoint file.
            File outputFile = new File(getFilesDir(), "checkpoint.ckpt");
            if(outputFile.exists()) {
                Map<String, Object> inputss = new HashMap<>();
                inputss.put("checkpoint_path", outputFile.getAbsolutePath());
                Map<String, Object> outputss = new HashMap<>();
                anotherInterpreter.runSignature(inputss, outputss, "restore");
            }
            return anotherInterpreter;
        }

    }


    class MyRunnable implements Runnable{

        @Override
        public void run() {
            int rescount=0;
            ArrayList<String> actionlist = new ArrayList<>();
            ArrayList<Float> accurencylist = new ArrayList<>();
            ArrayList<Long> delaylist = new ArrayList<>();    //每个线程自己的list
            lock.lock();
            if(Thread.currentThread().getName().equals("线程1"))mInterpreter = TFLiteLoader.newInstance(getApplicationContext()).get("trainable_model.tflite");
            if(Thread.currentThread().getName().equals("线程2"))mInterpreter2 = TFLiteLoader.newInstance(getApplicationContext()).get("watch_inference.tflite");
            if(Thread.currentThread().getName().equals("线程3"))mInterpreter3 = TFLiteLoader.newInstance(getApplicationContext()).get("watch_inference.tflite");
            File outputFile = new File(getFilesDir(), "checkpoint.ckpt");
            if(outputFile.exists()) {
                Log.d("","找到检查点了");
                Map<String, Object> inputss = new HashMap<>();
                inputss.put("checkpoint_path", outputFile.getAbsolutePath());
                Map<String, Object> outputss = new HashMap<>();
                mInterpreter.runSignature(inputss, outputss, "restore");
            }

            lock.unlock();
            int count=0;
            int lastaccnum=-1;
            while(true){
//                Log.d("","数据量"+acclist.size()+" "+grylist.size());
                Log.d("","线程："+Thread.currentThread().getName());
                if(lastaccnum==acclist.size()&&(acclist.size()<count+500||grylist.size()<count+500))
                {
//                    try {
//                        Thread.sleep(2000);
//                    } catch (InterruptedException e) {
//                        e.printStackTrace();
//                    }
                    Log.d("","线程："+Thread.currentThread().getName()+"结束了！！！！！！！！！！！！");
                    float total=0;
                    float i=0;
                    for(float f:accurencylist){
                        total+=f;
                        i++;
                    }
                    total/=i;
                    para.accuracy=total;

                    Log.d("",""+para.accuracy);

                    long delay=0;
                    long j=0;
                    for(long l:delaylist){
                        delay+=l;
                        j++;
                    }
                    delay/=j;
                    para.delay=delay;
                    para.calculate=1;

                    lock.lock();
                    //输出文件。2
                    try {
                        FileOutputStream os = null;
                        File dir = new File(Environment.getExternalStorageDirectory(), "TF");
                        FileOutputStream osTotal = null;
                        if (para.timeFlag == 0) {
                            SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss");
                            para.time = format.format(new Date());
                            para.timeFlag = 1;
                        }
                        File test = new File(dir, "ID#" + para.time + para.totalID);
                        File check = new File(dir, "check.csv");
                        osTotal = new FileOutputStream(check, true);
                        File actiondir = new File(test, actionnow);
                        String s = "";String checks = "";
                        if(para.firstwrite==0) {
                            para.firstwrite=1;
                            Log.d("", "大小：" + accurencylist.size());

                            if (!dir.exists()) {
                                dir.mkdirs();
                            }




                            if (!check.exists()) {
                                check.createNewFile();
                            }




//                        osTotal.write(s.getBytes());
//                        osTotal.flush();


                            if (!test.exists()) {
                                test.mkdirs();
                            }

                            if (!actiondir.exists()) {
                                actiondir.mkdirs();
                            }
                            File accf = new File(actiondir, "acc#" + para.time + para.sensorID + ".csv");
                            if (!accf.exists()) {
                                accf.createNewFile();
                            }

                            os = new FileOutputStream(accf, true);
                            for (accdata a : acclist) {
                                s = a.x + "," + a.y + "," + a.z + "\n";
                                os.write(s.getBytes());
                                os.flush();
                            }
                            os.close();

                            File gryf = new File(actiondir, "gry#" + para.time + para.sensorID + ".csv");
                            if (!gryf.exists()) {
                                gryf.createNewFile();
                            }
                            os = new FileOutputStream(gryf, true);
                            for (grydata a : grylist) {
                                s = a.x + "," + a.y + "," + a.z + "\n";
//                            Log.d("",s);
                                os.write(s.getBytes());
                                os.flush();
                            }
                            os.close();
                        }
                        Log.d("",Thread.currentThread().getName()+"1111111111");

                        int modelIndex=1;
                        for(;modelIndex<4;modelIndex++){
                            if(Thread.currentThread().getName().equals("线程"+modelIndex)){
                                File model=new File(actiondir,"model"+modelIndex+"#"+para.time+para.modelID);
                                if(!model.exists()){
                                    model.mkdirs() ;
                                }

                                File predictf = new File(model, "predict#"+para.time+para.modelID+".csv");
                                if (!predictf.exists()) {
                                    predictf.createNewFile();
                                }
                                os = new FileOutputStream(predictf, true);
                                int c=0;//计数器
                                for (String a : actionlist) {
                                    c++;
                                    s=c+","+a+"\n";
                                    os.write(s.getBytes());
                                    os.flush();
                                }
                                os.close();
                                Log.d("",Thread.currentThread().getName()+"2222222222");

                                File accuracyf = new File(model, "accuracy#"+para.time+para.modelID+".csv");
                                if (!accuracyf.exists()) {
                                    accuracyf.createNewFile();
                                }
                                os = new FileOutputStream(accuracyf, true);
                                c=0;//计数器
                                for (Float a : accurencylist) {
                                    c++;
                                    s=c+","+a+"\n";
                                    os.write(s.getBytes());
                                    os.flush();
                                }
                                os.close();


                                File delayf = new File(model, "delay#"+para.time+para.modelID+".csv");
                                if (!delayf.exists()) {
                                    delayf.createNewFile();
                                }
                                os = new FileOutputStream(delayf, true);
                                c=0;//计数器
                                for (Long a : delaylist) {
                                    c++;
                                    s=c+","+a+"\n";
                                    os.write(s.getBytes());
                                    os.flush();
                                }
                                os.close();

                                checks="ID#"+para.time+para.totalID+","
                                        +actionnow+","
                                        +"acc#"+para.time+para.sensorID+".csv"+","
                                        +"gry#"+para.time+para.sensorID+".csv"+","
                                        +"predict#"+para.time+para.modelID+".csv"+","
                                        +"accuracy#"+para.time+para.modelID+".csv"+","
                                        +"delay#"+para.time+para.modelID+".csv"+"\n";
                                osTotal.write(checks.getBytes());
                                osTotal.flush();

                                para.modelID++;

                            }
                        }


                        osTotal.close();

                    } catch (IOException e) {
                            e.printStackTrace();
                        }





                    //输出文件，结束


                    if(Thread.currentThread().getName().equals("线程1")){
                        Log.d("","已关闭");
                        mInterpreter.close();
                        threadlist.remove("t1");
                    }
                    if(Thread.currentThread().getName().equals("线程2")){
                        mInterpreter2.close();
                        threadlist.remove("t2");
                    }
                    if(Thread.currentThread().getName().equals("线程3")){
                        mInterpreter3.close();
                        threadlist.remove("t3");
                    }
                    Log.d("","剩余线程数"+Thread.activeCount());
                    lock.unlock();
                    if(threadlist.size()==0){
                    Intent intent=new Intent(testing.this,testResult.class);  //倒计时结束，进入测试记录页面

                    startActivity(intent);}


                    break;
                }
                if(acclist.size()>count+500&&grylist.size()>count+500){
                    Log.d("",count+500+" "+acclist.size()+" "+grylist.size());
                    float[][][] data=new float[1][100][6];
//                Log.d("","zhelidaxiao"+acclist.size());
                    int i=count;
                    for(;i<count+500;i+=5){
//                        Log.d("","线程："+Thread.currentThread().getName()+" "+i+" "+acclist.size());
//                        Log.d("","i:" +i+" "+(i-count)/5);
                        accdata a= acclist.get(i);
                            data[0][(i-count)/5][0]=a.x;
                            data[0][(i-count)/5][1]=a.y;
                            data[0][(i-count)/5][2]=a.z;
                    }
//                    Log.d("","XXX");
                    for(i=count;i<count+500;i+=5){
//                        Log.d("","i:" +i);
                        grydata a= grylist.get(i);
                        data[0][(i-count)/5][3]=a.x;
                        data[0][(i-count)/5][4]=a.y;
                        data[0][(i-count)/5][5]=a.z;

                    }
//                    Log.d("","YYY");
                    float[][] res=new float[1][6];

                    long currentTime1=System.currentTimeMillis();
                    Log.d("","线程："+Thread.currentThread().getName()+" "+data[0][0][0]+" "+data[0].length+" "+data[0][0].length);
                    //双interpreter
                    Map<String, Object> output = new HashMap<>();
                    Map<String, Object> input = new HashMap<>();

                    input.put("x", data);
                    output.put("output",res);
                    if(Thread.currentThread().getName().equals("线程1"))mInterpreter.runSignature(input, output, "infer");;
                    if(Thread.currentThread().getName().equals("线程2"))mInterpreter2.run(data,res);
                    if(Thread.currentThread().getName().equals("线程3"))mInterpreter3.run(data,res);
                    rescount++;
                    Log.d("","线程："+Thread.currentThread().getName()+"跑了"+rescount+"次");
//                    lock.lock();
//                    mInterpreter.run(data,res);
//                    lock.unlock();
                    Log.d("","线程："+Thread.currentThread().getName()+" "+res[0][0]);
                    long currentTime2=System.currentTimeMillis();
                    Log.d("","delay="+(currentTime2-currentTime1));
                    delaylist.add(currentTime2-currentTime1);
                    float max=-1;
                    int maxindex=-1;
                    for(int j=0 ; j<6; j++){
                        Log.d("result-->", String.valueOf(res[0][j]));
                        if(max<res[0][j]){
                            max=res[0][j];
                            maxindex=j;
                        }
                    }
                    Log.d("",para.actionName[maxindex]+" "+max);
                    actionlist.add(para.actionName[maxindex]);

                        accurencylist.add(res[0][actionindex]);
                        actionpredict=para.actionName[maxindex];

                    count+=50;
                    lastaccnum=acclist.size();

                }
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        flag=0;
        mInterpreter=null;
        mInterpreter2=null;
        Log.d("",acclist.size()+"  ");
        MyRunnable myRun = new MyRunnable();
        //定义两个interpreter

        super.onCreate(savedInstanceState);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);//保持不熄屏
        permissionLauncher=registerForActivityResult(new ActivityResultContracts.RequestPermission(), result -> {});
        permissionLauncher.launch(android.Manifest.permission.BODY_SENSORS);
        this.mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
        this.mMySensorEventListener = new MySensorEventListener();
        Thread t = new Thread(myRun, "线程1");
        Thread t2 = new Thread(myRun, "线程2");
        Thread t3 = new Thread(myRun, "线程3");
        setContentView(R.layout.activity_testing);
        text1 = (TextView) findViewById(R.id.text1);
        showaction = (TextView) findViewById(R.id.action);

        //输出文件。1
        ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},1);



        para.setTimeIndex = para.setTimeIndex + 1;
        remainTime = (TextView) findViewById(R.id.remainTime);
        text1.setText("测试第" + para.setTimeIndex + "/" + para.action.size() + "个动作中， 动作是" + para.action.get(para.setTimeIndex - 1));
        actionnow=para.action.get(para.setTimeIndex - 1);
        for(int j=0;j<6;j++){
            if(para.actionName[j].equals(actionnow)){

                actionindex=j;} Log.d("",para.actionName[j]+" "+actionnow);
        }
    if(para.modellist.indexOf("model1")!=-1) {
        Log.d("","有1！！！！！！！！！！");
        t.start();
        threadlist.add("t1");
    }
        if(para.modellist.indexOf("model2")!=-1){
            Log.d("","有2！！！！！！！！！！");
        t2.start();
        threadlist.add("t2");}
        if(para.modellist.indexOf("model3")!=-1){
            Log.d("","有3！！！！！！！！！！");
            t3.start();
            threadlist.add("t3");}
        timer =new CountDownTimer(para.timelist.get(para.setTimeIndex - 1) * 1000, 500) {
            @Override

            public void onTick(long l) {
                remainTime.setText("剩余时长："+l/1000 +"s");
//                Log.d("","数据量"+acclist.size()+" "+grylist.size());
                showaction.setText("推测动作："+actionpredict);
                //显示剩余时长，倒计时
            }

            @Override
            public void onFinish() {
                mSensorManager.unregisterListener(mMySensorEventListener);
                Log.d("","Finish!!!!!!!!!!!!!!");
//                Intent intent=new Intent(testing.this,testResult.class);  //倒计时结束，进入测试记录页面
//
//                startActivity(intent);
            }
        };
    }

    protected void onResume() {
        super.onResume();
        Sensor accelerometerSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); //注册加速度，1
        mSensorManager.registerListener(mMySensorEventListener, accelerometerSensor, SensorManager.SENSOR_DELAY_FASTEST); //
        Sensor gyroscopeSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE); //1
        mSensorManager.registerListener(mMySensorEventListener, gyroscopeSensor, SensorManager.SENSOR_DELAY_FASTEST); //1
    }

    protected void onPause() {  //计时结束，自动跳转
        super.onPause();
        if (mSensorManager == null) {
            return;
        }
        //unregister all listener
        mSensorManager.unregisterListener(mMySensorEventListener);
    }

    private class MySensorEventListener implements SensorEventListener {
        @Override
        public void onSensorChanged(SensorEvent event) {
            if(flag==0){
                timer.start();
                flag=1;
            }
//            Log.d("", event.sensor.getType() + "");
            if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {  //gettype,看传感器的编号
                mAccelerometerReading = event.values;  //1
                accdata a = new accdata();
                a.x = event.values[0];
                a.y = event.values[1];
                a.z = event.values[2];
                a.timestamp = event.timestamp;
                acclist.add(a);

//                Log.d("","daxiao"+acclist.size());
                // Log.d(TAG, "accelerometer data[x:" + event.values[0] + ", y:" + event.values[1] + ", z:" + event.values[2] + ",time:"+event.timestamp+"]");
                //显示加速度
            } else if (event.sensor.getType() == Sensor.TYPE_GYROSCOPE) { //陀螺仪
                grydata a = new grydata();
                a.x = event.values[0];
                a.y = event.values[1];
                a.z = event.values[2];
                a.timestamp = event.timestamp;
                grylist.add(a);
//                Log.d(TAG, "gyroscope data[x:" + event.values[0] + ", y:" + event.values[1] + ", z:" + event.values[2] + "]");
            }
        }

        @Override
        public void onAccuracyChanged(Sensor sensor, int i) {

        }

    }
}
